package com.winchain.chainbill.receivables.biz.impt.service.impl;

import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.cache.Cache;
import com.shell.bee.cache.CacheBuilder;
import com.shell.bee.entity.auth.AuthOrgan;
import com.shell.bee.report.excel.ExcelParser;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.Validator;
import com.winchain.chainbill.ChainBillUtil;
import com.winchain.chainbill.basic.cus.po.CusRec;
import com.winchain.chainbill.basic.cus.po.CusRel;
import com.winchain.chainbill.basic.cus.service.CusRecService;
import com.winchain.chainbill.basic.cus.service.CusRelService;
import com.winchain.chainbill.receivables.ReceivablesUtil;
import com.winchain.chainbill.receivables.base.po.ArOperation;
import com.winchain.chainbill.receivables.base.po.ArRecord;
import com.winchain.chainbill.receivables.base.service.ArRecordService;
import com.winchain.chainbill.receivables.biz.impt.rx.BatchReceivablesImptEvent;
import com.winchain.chainbill.receivables.biz.impt.rx.ReceivablesImptSubscriber;
import com.winchain.chainbill.receivables.biz.impt.service.ReceivablesImptService;
import com.winchain.chainbill.receivables.biz.impt.vo.ReadEcho;
import com.winchain.chainbill.risk.base.po.RmAccess;
import com.winchain.chainbill.risk.base.service.RmAccService;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import rx.Observable;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

@Service("receivablesImptService")
public class ReceivablesImptServiceImpl implements ReceivablesImptService {
	@Autowired
	private CusRecService basCusService;
	@Autowired
	private CusRelService basCusRelService;
	@Autowired
	private RmAccService rmAccService;
	@Autowired
	private ArRecordService arRecordService;
	@Autowired
	private ReceivablesImptSubscriber receivablesImptSubscriber;
	private static final String SEPARATOR = ", ";
	private static final int MAX_LENGTH = 512;
	private static final Cache<String, ReadEcho> READECHO_CACHE = CacheBuilder.newBuilder().build();

	private boolean isFin() {
		String cusType = CommonDataUtil.getCurEnt().getCusType();

		boolean is = false;
		if ("FINNER".equals(cusType)) {
			is = true;
		}
		return is;
	}

	public ReadEcho read(File file) throws Exception {
		List<ArRecord> records = ExcelParser.parseExcel(file.getPath(), ArRecord.class);
		ReadEcho echo = check(records, false);
		if ((StringUtil.emptyAndNull(echo.getError())) && (echo.getData().size() > 0)) {
			READECHO_CACHE.put(getArRecordCacheKey(file.getName()), echo, 120);
		}
		return echo;
	}

	private ReadEcho check(List<ArRecord> records, boolean impt) {
		StringBuffer error = new StringBuffer("");
		StringBuffer warning = new StringBuffer("");
		StringBuffer outSuppliers = new StringBuffer("");
		List<ArRecord> allData = new ArrayList();
		List<ArRecord> data = new ArrayList();
		List<ArRecord> unaccess = new ArrayList();
		List<ArRecord> exceedUpperLimit = new ArrayList();
		List<ArRecord> exist = new ArrayList();
		BigDecimal totalAmount = new BigDecimal(0);
		int count = 0;
		String sellerId = "";
		String sellerName = "";
		String buyerId = "";
		String buyerName = "";
		if (!isFin()) {
			buyerId = CommonDataUtil.getCurEntId();
			buyerName = CommonDataUtil.getCurEntName();
		}
		String[] stringArray = null;
		String errorString = "";
		String pmtPeriodHasNoProblem = "1";
		int line = 0;
		for (int i = 0; i < records.size(); i++) {
			line = i + 1;
			ArRecord record = (ArRecord) records.get(i);

			sellerName = record.getSellerName();
			if (isFin()) {
				buyerName = record.getBuyerName();
				stringArray = checkNull(buyerName, "��������", line);
				errorString = stringArray[0];
				buyerId = stringArray[1];
				if (StringUtil.notEmpty(errorString)) {
					error.append(errorString);
					break;
				}
				record.setBuyerId(buyerId);
			} else {
				record.setBuyerId(buyerId);
				record.setBuyerName(buyerName);
			}
			stringArray = checkNull(sellerName, "������", line);
			errorString = stringArray[0];
			sellerId = stringArray[1];
			if (StringUtil.notEmpty(errorString)) {
				error.append(errorString);
			} else {
				record.setSellerId(sellerId);

				RmAccess access = this.rmAccService.getAccessByBuyerAndSellerId(buyerId, sellerId);
				if (!checkAccess(access)) {
					if (isFin()) {
						outSuppliers.append(buyerName).append("����").append(sellerName).append(", ");
					} else {
						outSuppliers.append(sellerName).append(", ");
					}
					record.setAccess(false);
					unaccess.add(record);
				} else {
					record.setAccess(true);
					record.setConvertRatio(access.getConvertRatio());
					if (!impt) {
						stringArray = checkData(record, access, line);
						error.append(stringArray[0]);
						warning.append(stringArray[1]);
						pmtPeriodHasNoProblem = stringArray[2];

						error.append(checkLength(record, line));
					}
					if (("1".equals(pmtPeriodHasNoProblem)) || (impt)) {
						handleDate(record);
					}
					initRecord(record);
					count++;
					if ((record.getExceedUpperLimit()) || (record.getExist())) {
						if (record.getExceedUpperLimit()) {
							exceedUpperLimit.add(record);
						} else if (record.getExist()) {
							exist.add(record);
						}
					} else {
						data.add(record);
					}
					totalAmount = totalAmount.add(record.getArMoney());
				}
			}
		}
		allData.addAll(unaccess);
		allData.addAll(exist);
		allData.addAll(exceedUpperLimit);
		allData.addAll(data);

		ReadEcho echo = new ReadEcho();

		data.addAll(exist);
		data.addAll(exceedUpperLimit);
		echo.setData(data);
		echo.setAllData(allData);
		echo.setError(error.toString());
		echo.setWarning(warning.toString());
		echo.setOutSuppliers(outSuppliers.toString());
		echo.setTotalAmount(totalAmount);
		echo.setCount(count);
		return echo;
	}

	private void initRecord(ArRecord record) {
		String batchNo = SystemUtil.getUUID();
		record.setBatchNo(batchNo);

		record.setArState("S");
		record.setOptSeq(Integer.valueOf(-1));
		record.setCreatorId(CommonDataUtil.getUserId());
		record.setCreateTime(DateUtil.getSystemDateTime());

		BigDecimal creditMoney = ReceivablesUtil.calcCreditMoney(record.getArMoney(), record.getConvertRatio(),
				record.getPmtRatio());
		record.setCreditMoney(creditMoney);
		record.setDecMoney(new BigDecimal(0));
	}

	private void handleDate(ArRecord record) {
		String pmtPeriod = record.getPmtPeriod();
		String days = StringUtil.getFirstNumberFromStr(pmtPeriod);
		record.setPmtPeriod(days);

		String beginDate = record.getCheckDate();

		beginDate = beginDate.substring(0, beginDate.length() - 2) + "01";
		if ("30".equals(days)) {
			record.setPmtDate(DateUtil.getDateOffsetWithDayType(beginDate, 1, 1));
		} else if ("60".equals(days)) {
			record.setPmtDate(DateUtil.getDateOffsetWithDayType(beginDate, 2, 1));
		} else if ("90".equals(days)) {
			record.setPmtDate(DateUtil.getDateOffsetWithDayType(beginDate, 3, 1));
		}
	}

	private String[] checkNull(String cusName, String cusDes, int line) {
		StringBuffer error = new StringBuffer();
		String cusId = null;
		String[] retValue = new String[2];
		if (StringUtil.empty(cusName)) {
			error.append("��").append(line).append("��: ").append(cusDes).append("��������;").append("$");
		} else {
			CusRec cus = new CusRec();
			cus.setCusName(cusName);
			cus.setCusState("E");
			cus = (CusRec) this.basCusService.selectOne(cus);
			if (null == cus) {
				error.append("��").append(line).append("��: ").append(cusDes).append("[").append(cusName).append("]")
						.append("������;").append("$");
			} else {
				cusId = cus.getCusId();
				if (!beMyCustomer(cusId)) {
					error.append("��").append(line).append("��: ").append(cusDes).append("[").append(cusName)
							.append("]").append("������������;").append("$");
				}
			}
		}
		retValue[0] = error.toString();
		retValue[1] = cusId;
		return retValue;
	}

	private boolean beMyCustomer(String cusId) {
		CusRel cusRel = new CusRel();
		cusRel.setSrcId(CommonDataUtil.getCurEntId());
		cusRel.setTgtId(cusId);
		cusRel = (CusRel) this.basCusRelService.selectOne(cusRel);

		return cusRel != null;
	}

	private boolean checkAccess(RmAccess access) {
		boolean retValue = false;
		if (access != null) {
			String outputAvl = access.getOutputAvl();
			String loanAvl = access.getLoanAvl();
			if (("1".equals(outputAvl)) || ("1".equals(loanAvl))) {
				retValue = true;
			}
		}
		return retValue;
	}

	private String[] checkData(ArRecord record, RmAccess access, int line) {
		StringBuffer error = new StringBuffer();
		StringBuffer warning = new StringBuffer();
		String[] retValue = new String[3];

		String checkDate = record.getCheckDate();
		if (StringUtil.empty(checkDate)) {
			error.append("��").append(line).append("��: ������������������������;").append("$");
			checkDate = null;
		} else if (!Validator.isDateYyyyMMdd(checkDate)) {
			error.append("��").append(line).append("��: ������������������ yyyy/m/d;").append("$");
			checkDate = null;
		}
		BigDecimal arMoney = record.getArMoney();
		BigDecimal arUpperLim = access.getArUpperLim();
		if (null == arMoney) {
			error.append("��").append(line).append("��: ��������������������������;").append("$");
		} else if (arMoney.compareTo(new BigDecimal(0)) == -1) {
			error.append("��").append(line).append("��: ��������������������0;").append("$");
		} else if (arMoney.compareTo(arUpperLim) > 0) {
			record.setExceedUpperLimit(true);
			warning.append("��").append(line).append("��: ����������������������������������������;").append("$");
		}
		String pmtPeriod = record.getPmtPeriod();
		String pmtPeriodHasNoProblem = "0";
		if (StringUtil.empty(pmtPeriod)) {
			error.append("��").append(line).append("��: ������������;").append("$");
		} else if ((!"OA30��".equals(pmtPeriod)) && (!"OA60��".equals(pmtPeriod)) && (!"OA90��".equals(pmtPeriod))) {
			error.append("��").append(line).append("��: ��������������:0A30��,0A60��,0A90��  ����������;").append("$");
		} else {
			pmtPeriodHasNoProblem = "1";
		}
		BigDecimal pmtRatio = record.getPmtRatio();
		if (null == pmtRatio) {
			error.append("��").append(line).append("��: ��������������������������;").append("$");
		} else if ((pmtRatio.compareTo(new BigDecimal(100)) > 0) || (pmtRatio.compareTo(new BigDecimal(0)) <= 0)) {
			error.append("��").append(line).append("��: ����������������������0��������100������;").append("$");
		}
		String sellerName = record.getSellerName();
		if ((null != checkDate) && (null != arMoney)
				&& (checkDuplicated(record.getBuyerName(), checkDate, sellerName, arMoney))) {
			record.setExist(true);
			warning.append("��").append(line).append("��: ������������������������������;").append("$");
		}
		retValue[0] = error.toString();
		retValue[1] = warning.toString();
		retValue[2] = pmtPeriodHasNoProblem;
		return retValue;
	}

	private StringBuffer checkLength(ArRecord record, int line) {
		StringBuffer error = new StringBuffer();

		String contractNo = record.getContractNo();
		if (StringUtil.empty(contractNo)) {
			error.append("��").append(line).append("��: ����������������������;").append("$");
		} else if (contractNo.length() > 512) {
			error.append("��").append(line).append("��: ��������������������������").append(512).append("������;")
					.append("$");
		}
		String storageNo = record.getStorageNo();
		if ((StringUtil.notEmpty(storageNo)) && (storageNo.length() > 512)) {
			error.append("��").append(line).append("��: ������������������������").append(512).append("������;")
					.append("$");
		}
		String invoiceNo = record.getInvoiceNo();
		if ((StringUtil.notEmpty(invoiceNo)) && (invoiceNo.length() > 512)) {
			error.append("��").append(line).append("��: ����������������������").append(512).append("������;")
					.append("$");
		}
		String remark = record.getRemark();
		if ((StringUtil.notEmpty(remark)) && (remark.length() > 512)) {
			error.append("��").append(line).append("��: ��������������������").append(512).append("������;")
					.append("$");
		}
		return error;
	}

	private boolean checkDuplicated(String buyerName, String checkDate, String sellerName, BigDecimal arMoney) {
		boolean duplicated = false;
		Example example = new Example(ArRecord.class);
		Example.Criteria criteria = example.createCriteria();

		criteria.andEqualTo("buyerName", buyerName);
		criteria.andEqualTo("checkDate", checkDate);
		criteria.andEqualTo("sellerName", sellerName);
		criteria.andEqualTo("arMoney", arMoney);
		criteria.andNotEqualTo("arState", "6");

		List<ArRecord> list = this.arRecordService.selectByExample(example);
		if ((null != list) && (list.size() > 0)) {
			duplicated = true;
		}
		return duplicated;
	}

	private String getArRecordCacheKey(String fileName) {
		StringBuffer buffer = new StringBuffer("ar_impt");
		buffer.append("-").append(CommonDataUtil.getUserId());
		buffer.append("-").append(fileName);
		return buffer.toString();
	}

	public void impt(File file) throws Exception {
		ReadEcho echo = (ReadEcho) READECHO_CACHE.get(getArRecordCacheKey(file.getName()));
		if (echo == null) {
			List<ArRecord> records = ExcelParser.parseExcel(file.getPath(), ArRecord.class);
			echo = check(records, true);
		}
		BatchReceivablesImptEvent event = new BatchReceivablesImptEvent();
		event.setRecs(echo.getData());

		ArOperation opt = new ArOperation();
		opt.setBizType("ar_impt");
		opt.setState("S");
		opt.setOptCode("00");
		opt.setNextState("0");

		String limitDate = ChainBillUtil.getLimitDate("AR_IMPT_REV_LIM_DATE");
		opt.setLimitDate(limitDate);
		opt.setRemark("������������");
		event.setOperation(opt);

		Observable<BatchReceivablesImptEvent> observers = Observable.just(event);

		observers.subscribe(this.receivablesImptSubscriber);
	}
}
